home *** CD-ROM | disk | FTP | other *** search
- <h1>Acquisition</h1>
- <p> <a href="COPYRIGHT.html">Copyright (C) 1996-1998, Digital Creations</a>.</p>
-
- <p> Acquisition <a href="#1">[1]</a> is a mechanism that allows objects to obtain
- attributes from their environment. It is similar to inheritence,
- except that, rather than traversing an inheritence hierarchy
- to obtain attributes, a containment hierarchy is traversed.</p>
-
- <p> The <a href="ExtensionClass.html">ExtensionClass</a>. release includes mix-in
- extension base classes that can be used to add acquisition as a
- feature to extension subclasses. These mix-in classes use the
- context-wrapping feature of ExtensionClasses to implement
- acquisition. Consider the following example:</p>
- <PRE>
- import ExtensionClass, Acquisition
-
- class C(ExtensionClass.Base):
- color='red'
-
- class A(Acquisition.Implicit):
-
- def report(self):
- print self.color
-
- a=A()
- c=C()
- c.a=A()
-
- c.a.report() # prints 'red'
-
- d=C()
- d.color='green'
- d.a=a
-
- d.a.report() # prints 'green'
-
- a.report() # raises an attribute error
-
- </PRE>
-
- <p> The class <code>A</code> inherits acquisition behavior from
- <code>Acquisition.Implicit</code>. The object, <code>a</code>, "has" the color of
- objects <code>c</code> and <code>d</code> when it is accessed through them, but it
- has no color by itself. The object <code>a</code> obtains attributes
- from it's environment, where it's environment is defined by
- the access path used to reach <code>a</code>.</p>
-
- <h2>Acquisition wrappers</h2>
- <p> When an object that supports acquisition is accessed through
- an extension class instance, a special object, called an
- acquisition wrapper, is returned. In the example above, the
- expression <code>c.a</code> returns an acquisition wrapper that
- contains references to both <code>c</code> and <code>a</code>. It is this wrapper
- that performs attribute lookup in <code>c</code> when an attribute
- cannot be found in <code>a</code>.</p>
-
- <p> Aquisition wrappers provide access to the wrapped objects
- through the attributes <code>aq_parent</code>, <code>aq_self</code>, <code>aq_base</code>.
- In the example above, the expressions:</p>
- <PRE>
- 'c.a.aq_parent is c'
-
- </PRE>
-
- <p> and:</p>
- <PRE>
- 'c.a.aq_self is a'
-
- </PRE>
-
- <p> both evaluate to true, but the expression:</p>
- <PRE>
- 'c.a is a'
-
- </PRE>
-
- <p> evaluates to false, because the expression <code>c.a</code> evaluates
- to an acquisition wrapper around <code>c</code> and <code>a</code>, not <code>a</code> itself.</p>
-
- <p> The attribute <code>aq_base</code> is similar to <code>aq_self</code>. Wrappers may be
- nested and <code>aq_self</code> may be a wrapped object. The <code>aq_base</code>
- attribute is the underlying object with all wrappers removed.</p>
-
-
- <h2>Acquisition Control</h2>
- <p> Two styles of acquisition are supported in the current
- ExtensionClass release, implicit and explicit aquisition.</p>
-
- <h3>Implicit acquisition</h3>
- <p> Implicit acquisition is so named because it searches for
- attributes from the environment automatically whenever an
- attribute cannot be obtained directly from an object or
- through inheritence.</p>
-
- <p> An attribute may be implicitly acquired if it's name does
- not begin with an underscore, <code>_</code>.</p>
-
- <p> To support implicit acquisition, an object should inherit
- from the mix-in class <code>Acquisition.Implicit</code>.</p>
-
-
- <h3>Explicit Acquisition</h3>
- <p> When explicit acquisition is used, attributes are not
- automatically obtained from the environment. Instead, the
- method <code>aq_aquire</code> must be used, as in:</p>
- <PRE>
- print c.a.aq_acquire('color')
-
- </PRE>
-
- <p> To support explicit acquisition, an object should inherit
- from the mix-in class <code>Acquisition.Explicit</code>.</p>
-
-
- <h3>Controlled Acquisition</h3>
- <p> A class (or instance) can provide attribute by attribute control
- over acquisition. This is done by:</p>
-
- <ul><li><p>subclassing from <code>Acquisition.Explicit</code>, and</p>
-
-
- <li><p>setting all attributes that should be acquired to the special
- value: <code>Acquisition.Acquired</code>. Setting an attribute to this
- value also allows inherited attributes to be overridden with
- acquired ones.</p>
- <p> For example, in:</p>
- <PRE>
- class C(Acquisition.Explicit):
- id=1
- secret=2
- color=Acquisition.Acquired
- __roles__=Acquisition.Acquired
-
- </PRE>
-
- <p> The <em>only</em> attributes that are automatically acquired from
- containing objects are <code>color</code>, and <code>__roles__</code>. Note also
- that the <code>__roles__</code> attribute is acquired even though it's
- name begins with an underscore. In fact, the special
- <code>Acquisition.Acquired</code> value can be used in
- <code>Acquisition.Implicit</code> objects to implicitly acquire selected
- objects that smell like private objects.</p>
-
-
- </ul>
-
- <h3>Filtered Acquisition</h3>
- <p> The acquisition method, <code>aq_acquire</code>, accepts two optional
- arguments. The first of the additional arguments is a
- "filtering" function that is used when considering whether to
- acquire an object. The second of the additional arguments is an
- object that is passed as extra data when calling the filtering
- function and which defaults to <code>None</code>.</p>
-
- <p> The filter function is called with five arguments:</p>
-
- <ul><li><p>The object that the <code>aq_acquire</code> method was called on,</p>
-
-
- <li><p>The object where an object was found,</p>
-
-
- <li><p>The name of the object, as passed to <code>aq_acquire</code>,</p>
-
-
- <li><p>The object found, and</p>
-
-
- <li><p>The extra data passed to <code>aq_acquire</code>.</p>
-
- </ul>
- <p> If the filter returns a true object that the object found is
- returned, otherwise, the acquisition search continues.</p>
-
- <p> For example, in:</p>
- <PRE>
- from Acquisition import Explicit
-
- class HandyForTesting:
- def __init__(self, name): self.name=name
- def __str__(self):
- return "%s(%s)" % (self.name, self.__class__.__name__)
- __repr__=__str__
-
- class E(Explicit, HandyForTesting): pass
-
- class Nice(HandyForTesting):
- isNice=1
- def __str__(self):
- return HandyForTesting.__str__(self)+' and I am nice!'
- __repr__=__str__
-
- a=E('a')
- a.b=E('b')
- a.b.c=E('c')
- a.p=Nice('spam')
- a.b.p=E('p')
-
- def find_nice(self, ancestor, name, object, extra):
- return hasattr(object,'isNice') and object.isNice
-
- print a.b.c.aq_acquire('p', find_nice)
-
- </PRE>
-
- <p> The filtered acquisition in the last line skips over the first
- attribute it finds with the name <code>p</code>, because the attribute
- doesn't satisfy the condition given in the filter. The output of
- the last line is:</p>
- <PRE>
- spam(Nice) and I am nice!
-
- </PRE>
-
-
-
- <h2>Acquisition and methods</h2>
- <p> Python methods of objects that support acquisition can use
- acquired attributes as in the <code>report</code> method of the first example
- above. When a Python method is called on an object that is
- wrapped by an acquisition wrapper, the wrapper is passed to the
- method as the first argument. This rule also applies to
- user-defined method types and to C methods defined in pure mix-in
- classes.</p>
-
- <p> Unfortunately, C methods defined in extension base classes that
- define their own data structures, cannot use aquired attributes at
- this time. This is because wrapper objects do not conform to the
- data structures expected by these methods.</p>
-
-
- <h2>Acquiring Acquiring objects</h2>
- <p> Consider the following example:</p>
- <PRE>
- from Acquisition import Implicit
-
- class C(Implicit):
- def __init__(self, name): self.name=name
- def __str__(self):
- return "%s(%s)" % (self.name, self.__class__.__name__)
- __repr__=__str__
-
- a=C("a")
- a.b=C("b")
- a.b.pref="spam"
- a.b.c=C("c")
- a.b.c.color="red"
- a.b.c.pref="eggs"
- a.x=C("x")
-
- o=a.b.c.x
-
- </PRE>
-
- <p> The expression <code>o.color</code> might be expected to return <code>"red"</code>. In
- earlier versions of ExtensionClass, however, this expression
- failed. Acquired acquiring objects did not acquire from the
- environment they were accessed in, because objects were only
- wrapped when they were first found, and were not rewrapped as they
- were passed down the acquisition tree.</p>
-
- <p> In the current release of ExtensionClass, the expression "o.color"
- does indeed return <code>"red"</code>.</p>
-
- <p> When searching for an attribute in <code>o</code>, objects are searched in
- the order <code>x</code>, <code>a</code>, <code>b</code>, <code>c</code>. So, for example, the expression,
- <code>o.pref</code> returns <code>"spam"</code>, not <code>"eggs"</code>. In earlier releases of
- ExtensionClass, the attempt to get the <code>pref</code> attribute from <code>o</code>
- would have failed.</p>
-
- <p> If desired, the current rules for looking up attributes in complex
- expressions can best be understood through repeated application of
- the <code>__of__</code> method:</p>
-
- <dl><dt> <code>a.x</code><dd><p><code>x.__of__(a)</code></p>
-
-
- <dt> <code>a.b</code><dd><p><code>b.__of__(a)</code></p>
-
-
- <dt> <code>a.b.x</code><dd><p><code>x.__of__(a).__of__(b.__of__(a))</code></p>
-
-
- <dt> <code>a.b.c</code><dd><p><code>c.__of__(b.__of__(a))</code></p>
-
-
- <dt> <code>a.b.c.x</code><dd><p><code>x.__of__(a).__of__(b.__of__(a)).__of__(c.__of__(b.__of__(a)))</code></p>
-
- </dl>
- <p> and by keeping in mind that attribute lookup in a wrapper
- is done by trying to lookup the attribute in the wrapped object
- first and then in the parent object. In the expressions above
- involving the <code>__of__</code> method, lookup proceeds from left to right.</p>
-
- <p> Note that heuristics are used to avoid most of the repeated
- lookups. For example, in the expression: <code>a.b.c.x.foo</code>, the object
- <code>a</code> is searched no more than once, even though it is wrapped three
- times.</p>
-
-
- <p> <a name="1">[1]</a> Gil, J., Lorenz, D.,
- <a href="http://www.bell-labs.com/people/cope/oopsla/Oopsla96TechnicalProgramAbstracts.html#GilLorenz">Environmental Acquisition--A New Inheritance-Like Abstraction Mechanism</a>
- OOPSLA '96 Proceedings, ACM SIG-PLAN, October, 1996</p>
-
- <p>
- <TABLE BORDER=1 CELLPADDING=2>
- </TABLE></p>
-
-
-
-